package net;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import util.Debug;

/**
 * Manages single connections between nodes.
 * TODO: Wait for connection, handle idleness, receive and send messages
 * 
 * @author Emil Wall
 */
public class Connection extends Thread {
	
	private final int SLEEP_MS = 500;
	private ServerSocket serverSocket;
	private Socket socket = null;
	private ObjectInputStream ois = null;
	private ObjectOutputStream oos = null;
	private int index;
	private boolean terminated;
	
	public Connection(ServerSocket serverSocket, int index) {
		System.out.println(index+": Connection instantiated");
		this.serverSocket = serverSocket;
		this.index = index;
		terminated = false;
	}
	
	public void run() {
		System.out.println(index+": Establishing connection");
		try {
			socket = serverSocket.accept();
		} catch (IOException e) {
			if(Debug.on) {
				System.out.println(index+": failed to connect.");
			}
			if(Debug.verbose) {
				e.printStackTrace();
			}
		}
		System.out.println(index+": Connection established");
		bindIOStreams();
		System.out.println(index+": IO streams bound");
		
		while(true) {
			//TODO play ping pong
//			if(ois != null && oos != null) {
//				try {
//					oos.write(0);
//				} catch (IOException e) {
//					if(Debug.verbose) {
//						e.printStackTrace();
//					}
//				}
//			} else {
//				if(Debug.on) {
//					System.out.println(index+": streams = null");
//				}
//			}
			
			try {
				Thread.sleep(SLEEP_MS);
			} catch (InterruptedException e) {
				if(Debug.on && Debug.verbose) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public void close() {
		try {
			// Close input stream first or deadlock will occur.
			if (ois != null) {
				ois.close();
				ois = null;
			}
			if (oos != null) {
				oos.close();
				oos = null;
			}
			if (socket != null && socket.isConnected()) {
				socket.close();
			}
			socket = null;
		} catch (IOException e) {
			if(Debug.on) {
				System.err.println(index+": close:" + e.getMessage());
			}
			return;
		}
		terminated = true;
	}
	
	public boolean isTerminated() {
		return terminated;
	}
	
	/**
	 * Assigns class variables oos and ois [ObjectInputStream & 
	 * ObjectInputStream]
	 */
	private void bindIOStreams() {
		if(socket != null && socket.isConnected()) {
			try {
				// Get the output and input streams. 
				// Initialize output stream first or deadlock will occur.
				if(oos == null) {
					oos = new ObjectOutputStream(socket.getOutputStream());
				}
				if(ois == null) {
					ois = new ObjectInputStream(socket.getInputStream());
				}
			} catch (IOException e) {
				if(Debug.on) {
					System.err.println("bindIOStreams:" + e.getMessage());
				}
			}
		}
	}
	
}
